/** * Copyright 2015 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.arcbees.gaestudio.server.api.visualizer; import java.util.Collection; import java.util.List; import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import com.arcbees.gaestudio.server.dto.mapper.EntityMapper; import com.arcbees.gaestudio.server.guice.GaeStudioResource; import com.arcbees.gaestudio.server.service.visualizer.EntitiesService; import com.arcbees.gaestudio.shared.DeleteEntities; import com.arcbees.gaestudio.shared.dto.entity.EntityDto; import com.arcbees.gaestudio.shared.rest.EndPoints; import com.arcbees.gaestudio.shared.rest.UrlParameters; import com.google.api.client.repackaged.com.google.common.base.Strings; import com.google.appengine.api.datastore.Entity; import com.google.appengine.api.datastore.EntityNotFoundException; import com.google.appengine.api.datastore.Key; import com.google.common.base.Function; import com.google.common.collect.FluentIterable; @Path(EndPoints.ENTITIES) @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @GaeStudioResource public class EntitiesResource { private final EntitiesService entitiesService; private final EntityMapper entityMapper; @Inject EntitiesResource( EntitiesService entitiesService, EntityMapper entityMapper) { this.entitiesService = entitiesService; this.entityMapper = entityMapper; } @GET public Response getEntities(@QueryParam(UrlParameters.KIND) String kind, @QueryParam(UrlParameters.NAMESPACE) String namespace, @QueryParam(UrlParameters.OFFSET) Integer offset, @QueryParam(UrlParameters.LIMIT) Integer limit) { ResponseBuilder responseBuilder; if (kind == null) { responseBuilder = Response.status(Status.BAD_REQUEST); } else { Iterable<Entity> entities = entitiesService.getEntities(kind, namespace, offset, limit); List<EntityDto> entitiesDtos = entityMapper.mapEntitiesToDtos(entities); responseBuilder = Response.ok(entitiesDtos); } return responseBuilder.build(); } // TODO: Be able to generate entity base schema from the pojo that haven't been saved yet to the datastore // We will need to create an implementation to support Objectify, Twig persist, etc. // For objectify we can use : ObjectifyService.factory().getMetadataForEntity(String kind); // And call method metadata.toEntity @POST public Response createEmptyEntity(@QueryParam(UrlParameters.KIND) String kind) { ResponseBuilder responseBuilder; if (Strings.isNullOrEmpty(kind)) { responseBuilder = Response.status(Status.BAD_REQUEST); } else { Entity emptyEntity = entitiesService.createEmptyEntity(kind); if (emptyEntity == null) { responseBuilder = Response.status(Status.NOT_FOUND); } else { EntityDto emptyEntityDto = entityMapper.mapEntityToDto(emptyEntity); responseBuilder = Response.ok(emptyEntityDto); } } return responseBuilder.build(); } @DELETE public Response deleteEntities(@QueryParam(UrlParameters.KIND) String kind, @QueryParam(UrlParameters.NAMESPACE) String namespace, @QueryParam(UrlParameters.TYPE) DeleteEntities deleteType, @QueryParam(UrlParameters.KEY) String encodedKeys) { ResponseBuilder responseBuilder; if (isValidDeleteRequest(kind, namespace, deleteType, encodedKeys)) { entitiesService.deleteEntities(kind, namespace, deleteType, encodedKeys); responseBuilder = Response.noContent(); } else { responseBuilder = Response.status(Status.BAD_REQUEST); } return responseBuilder.build(); } @GET @Path(EndPoints.COUNT) public Response getCount(@QueryParam(UrlParameters.KIND) String kind, @QueryParam(UrlParameters.NAMESPACE) String namespace) { ResponseBuilder responseBuilder; if (Strings.isNullOrEmpty(kind)) { responseBuilder = Response.status(Status.BAD_REQUEST); } else { long count = entitiesService.getCount(kind, namespace); responseBuilder = Response.ok(count); } return responseBuilder.build(); } @PUT public Response updateEntities(List<EntityDto> entitiesDto) throws EntityNotFoundException { Collection<Entity> entities = FluentIterable.from(entitiesDto) .transform(new Function<EntityDto, Entity>() { @Override public Entity apply(EntityDto input) { return entityMapper.mapDtoToEntity(input); } }).toList(); List<Key> keys = entitiesService.put(entities); entities = entitiesService.getEntities(keys); return Response.ok(entityMapper.mapEntitiesToDtos(entities)).build(); } private boolean isValidDeleteRequest(String kind, String namespace, DeleteEntities deleteType, String encodedKeys) { boolean isValid = false; if (deleteType != null) { switch (deleteType) { case ALL: isValid = true; break; case KIND: isValid = kind != null; break; case NAMESPACE: isValid = namespace != null; break; case KIND_NAMESPACE: isValid = namespace != null && kind != null; break; case SET: isValid = !Strings.isNullOrEmpty(encodedKeys); break; default: isValid = false; break; } } return isValid; } }